package com.serkol.driving.learning.api;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.crypto.digest.MD5;
import com.serkol.annotation.IsLogin;
import com.serkol.bean.*;
import com.serkol.component.TokenUtils;
import com.serkol.constant.AuthConstant;
import com.serkol.constant.ResultCode;
import com.serkol.constant.ResultConstant;
import com.serkol.driving.learning.entity.LoginLog;
import com.serkol.driving.learning.entity.Users;
import com.serkol.driving.learning.service.LoginLogService;
import com.serkol.driving.learning.service.UsersService;
import com.serkol.exception.AuthException;
import com.serkol.exception.SerkolProjectException;
import com.serkol.driving.learning.handler.ParseUtils;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("api/oauth/login")
public class LoginApiController {


    @Autowired
    private UsersService userService;



    private TokenUtils tokenUtils;
    @Autowired
    private LoginLogService logService;




    @Autowired
    private WxMaService wxMaService;


  //  @Autowired
  //  private WechatMiniMessageService wechatMiniMessageService;

    /**
     * 获取客户端ip地址
     *
     * @param request
     * @return
     */
    public static String getCliectIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.trim() == "" || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        // 多个路由时，取第一个非unknown的ip
        final String[] arr = ip.split(",");
        for (final String str : arr) {
            if (!"unknown".equalsIgnoreCase(str)) {
                ip = str;
                break;
            }
        }
        return ip;
    }


    @PostMapping("/wxTest")
    @ResponseBody
    public Result wxTest(HttpServletRequest request, @RequestBody @Valid WxMiniConfig wxMiniConfig) throws SerkolProjectException, WxErrorException {
        tokenUtils = new TokenUtils(logService);
        System.out.println(wxMiniConfig);
        LoginLog loginLog = wxMiniConfig.getLoginLog();
        // loginLog.setIp(getCliectIp(request));
        Result result = new Result();

/*
        loginLog.setIp(getCliectIp(request));
        String openid = "o7eTd4pqafII42mNJ-eUMGiA237A";
        String sessionKey = "Test";
        System.out.println(openid);
        System.out.println(wxMiniConfig);
        Users byLogin = userService.findByLogin(openid);
        Map<String, Object> mapLogin = new HashMap<>();

        mapLogin = getToken(byLogin, loginLog, sessionKey);
        result.setData(mapLogin);
        result.setStatus(ResultConstant.SUCSESS);*/

        //   wxMaService.getUserService().
        //   result.setStatus(ResultConstant.TOKEN);
        return Result.failure();
    }

    @PostMapping("/account")
    @ResponseBody
    public Result account(HttpServletRequest request, @RequestBody @Valid LoginConfig loginConfig) throws SerkolProjectException, AuthException {
        tokenUtils = new TokenUtils(logService);
        String agent = request.getHeader("User-Agent");
        String myLanguage = request.getHeader("MyLanguage");
        String myVersion = request.getHeader("Version");
        String terminal = request.getHeader("terminal");

        String localName = request.getLocale().getDisplayLanguage();
//解析agent字符串
        UserAgent userAgent = UserAgent.parseUserAgentString(agent);
//获取浏览器对象
        Browser browser = userAgent.getBrowser();
//获取操作系统对象
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();

        System.out.println("浏览器名:" + browser.getName());
        System.out.println("浏览器类型:" + browser.getBrowserType());
        System.out.println("浏览器家族:" + browser.getGroup());
        System.out.println("浏览器生产厂商:" + browser.getManufacturer());
        System.out.println("浏览器使用的渲染引擎:" + browser.getRenderingEngine());
        System.out.println("浏览器版本:" + userAgent.getBrowserVersion());

        System.out.println("操作系统名:" + operatingSystem.getName());
        System.out.println("访问设备类型:" + operatingSystem.getDeviceType());
        System.out.println("操作系统家族:" + operatingSystem.getGroup());
        System.out.println("操作系统生产厂商:" + operatingSystem.getManufacturer());
        System.out.println(loginConfig);
        LoginLog loginLog = new LoginLog();
      //  loginLog.setTerminal(NumberUtils.toInt(terminal.isEmpty() ? String.valueOf('1') : String.valueOf(terminal), 0));
        loginLog.setMyLanguage(myLanguage);
        loginLog.setMyVersion(myVersion);
        loginLog.setLanguage(localName);
        loginLog.setBrand(operatingSystem.getManufacturer().getName());
        loginLog.setModel(operatingSystem.getName());
        loginLog.setSystemVersion(browser.getName());
        loginLog.setVersion(userAgent.getBrowserVersion().getVersion());
        loginLog.setIp(getCliectIp(request));
        Result result = new Result();
        //   DevicePlatform devicePlatform = device.getDevicePlatform();
        loginLog.setPlatform(operatingSystem.getDeviceType().getName());

        Users byLogin = userService.findByUserLogin(loginConfig);
        if (byLogin.getIsAdmin() == 1) {
            Map<String, Object> mapLogin = new HashMap<>();
            if (byLogin != null) {
                loginLog.setOpenId(byLogin.getOpenid());
                mapLogin = getToken(byLogin, loginLog, "");
                result.setData(mapLogin);
                result.setStatus(ResultConstant.SUCSESS);
                return result;
            } else {
                throw new AuthException(ResultCode.OK_CONTENT_NO);
            }
        } else {
            throw new AuthException(ResultCode.REQUEST_ERROR_UNAUTHORIZED);
        }


    }


    @PostMapping("/accountWechat")
    @ResponseBody
    public Result accountWechat(HttpServletRequest request, @RequestBody @Valid WxLoginConfig loginConfig) throws SerkolProjectException, AuthException {
        tokenUtils = new TokenUtils(logService);

        //   String terminal = request.getHeader("terminal");
        Result result = new Result();
        LoginLog loginLog = loginConfig.getLoginLog();
        //  loginLog.setTerminal(NumberUtils.toInt(terminal.isEmpty() ? String.valueOf('1') : String.valueOf(terminal), 0));
        loginLog.setIp(getCliectIp(request));
        Users byLogin = userService.findByUserLogin(loginConfig);
        Map<String, Object> mapLogin = new HashMap<>();
        if (byLogin != null) {
            loginLog.setOpenId(byLogin.getOpenid());
            if (loginConfig.getParentUserId() != null) {
                boolean isUser = userService.isUsers(loginConfig.getParentUserId());
                if (isUser) {
                    byLogin.setParentUserId(loginConfig.getParentUserId());
                }

            }
            mapLogin = getToken(byLogin, loginLog, "");
            result.setData(mapLogin);
            result.setStatus(ResultConstant.SUCSESS);
            return result;
        } else {
            throw new AuthException(ResultCode.OK_CONTENT_NO, "mini.userorpasserror");
        }


    }


    @PostMapping("/accountWechatMiniOpen")
    @ResponseBody
    public Result accountWechatMiniOpen(HttpServletRequest request, @RequestBody @Valid WxLoginMiniConfig loginConfig) throws SerkolProjectException, AuthException, WxErrorException {
        tokenUtils = new TokenUtils(logService);
        //     String terminal = request.getHeader("terminal");
        Result result = new Result();
        LoginLog loginLog = loginConfig.getLoginLog();
        //  loginLog.setTerminal(NumberUtils.toInt(terminal.isEmpty() ? String.valueOf('1') : String.valueOf(terminal), 0));
        loginLog.setIp(getCliectIp(request));
        Users byLogin = userService.findByUserLogin(loginConfig);
        Map<String, Object> mapLogin = new HashMap<>();
        if (byLogin != null) {
            System.out.println(wxMaService.getWxMaConfig().getAppid());
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(loginConfig.getCode());
            String openid = session.getOpenid();
            String sessionKey = session.getSessionKey();
            System.out.println(openid);
            System.out.println(loginConfig);
            loginLog.setOpenId(byLogin.getOpenid());
            if (loginConfig.getParentUserId() != null) {
                boolean isUser = userService.isUsers(loginConfig.getParentUserId());
                if (isUser) {
                    byLogin.setParentUserId(loginConfig.getParentUserId());

                }

            }


            byLogin.setOpenid(openid);
            userService.updateById(byLogin);

            loginLog.setOpenId(byLogin.getOpenid());
            mapLogin = getToken(byLogin, loginLog, sessionKey);

            //   wxMaService.getUserService().setUserStorage(mapText, sessionKey, openid);
            result.setData(mapLogin);
            result.setStatus(ResultConstant.SUCSESS);

            return result;
        } else {
            throw new AuthException(ResultCode.OK_CONTENT_NO, "mini.userorpasserror");
        }


    }

    @PostMapping("/accountWechatMini")
    @ResponseBody
    public Result accountWechatMini(HttpServletRequest request, @RequestBody @Valid WxLoginMiniConfig loginConfig) throws SerkolProjectException, AuthException, WxErrorException {
        tokenUtils = new TokenUtils(logService);
        //     String terminal = request.getHeader("terminal");
        Result result = new Result();
        LoginLog loginLog = loginConfig.getLoginLog();
        //  loginLog.setTerminal(NumberUtils.toInt(terminal.isEmpty() ? String.valueOf('1') : String.valueOf(terminal), 0));
        loginLog.setIp(getCliectIp(request));
        Users byLogin = userService.findByUserLogin(loginConfig);
        Map<String, Object> mapLogin = new HashMap<>();
        if (byLogin != null) {
            System.out.println(wxMaService.getWxMaConfig().getAppid());
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(loginConfig.getCode());
            String openid = session.getOpenid();
            String sessionKey = session.getSessionKey();
            System.out.println(openid);
            System.out.println(loginConfig);
            WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionKey, loginConfig.getEncryptedData(), loginConfig.getIv());
            if (userInfo != null) {
                loginLog.setOpenId(byLogin.getOpenid());

                Users usersDetail = ParseUtils.parseUsersDetail(userInfo);

                usersDetail.setOpenid(openid);
                if (loginConfig.getParentUserId() != null) {
                    boolean isUser = userService.isUsers(loginConfig.getParentUserId());
                    if (isUser) {
                        byLogin.setParentUserId(loginConfig.getParentUserId());

                    }

                }

                byLogin.setAvatar(userInfo.getAvatarUrl());
                byLogin.setNickname(userInfo.getNickName());
                byLogin.setSex(Integer.parseInt(userInfo.getGender()));
                // usersDetail.set(wxMaUserInfo.getCity());
                //   usersDetail.setCountry(wxMaUserInfo.getCountry());
                //  usersDetail.setLanguage(wxMaUserInfo.getLanguage());
                //  usersDetail.setOpenid(wxMaUserInfo);
                byLogin.setUnionid(userInfo.getUnionId());
                byLogin.setOpenid(openid);
                userService.updateById(byLogin);

                loginLog.setOpenId(byLogin.getOpenid());
                mapLogin = getToken(byLogin, loginLog, sessionKey);

                //   wxMaService.getUserService().setUserStorage(mapText, sessionKey, openid);
                result.setData(mapLogin);
                result.setStatus(ResultConstant.SUCSESS);

            } else {
                result.setStatus(ResultConstant.FAIL);
            }
            return result;
        } else {
            throw new AuthException(ResultCode.OK_CONTENT_NO, "mini.userorpasserror");
        }


    }


    @IsLogin
    @PostMapping("/refreshLogin")
    @ResponseBody
    public Result refreshLogin(HttpServletRequest request) throws SerkolProjectException, AuthException {
        tokenUtils = new TokenUtils(logService);
        Result result = new Result();
        LoginLog loginLog = AuthConstant.getLoginLog();
        loginLog.setIp(getCliectIp(request));
        Users byLogin = userService.findByUserId(loginLog.getUserId());
        Map<String, Object> mapLogin = new HashMap<>();
        if (byLogin != null) {
            loginLog.setId(null);
            loginLog.setOpenId(byLogin.getOpenid());
            mapLogin = getToken(byLogin, loginLog, "");
            result.setData(mapLogin);
            result.setStatus(ResultConstant.SUCSESS);
            return result;
        } else {
            throw new AuthException(ResultCode.OK_CONTENT_NO);
        }


    }

    @PostMapping("/miniLogin")
    @ResponseBody
    public Result miniLogin(HttpServletRequest request) throws SerkolProjectException, AuthException {
        tokenUtils = new TokenUtils(logService);
        //   String terminal = request.getHeader("terminal");
        Result result = new Result();
        LoginLog loginLog = AuthConstant.getLoginLog();
        //  loginLog.setTerminal(NumberUtils.toInt(terminal.isEmpty() ? String.valueOf('1') : String.valueOf(terminal), 0));
        loginLog.setIp(getCliectIp(request));
        Users byLogin = userService.findByUserId(loginLog.getUserId());
        Map<String, Object> mapLogin = new HashMap<>();
        if (byLogin != null) {
            loginLog.setOpenId(byLogin.getOpenid());
            mapLogin = getToken(byLogin, loginLog, "");
            result.setData(mapLogin);
            result.setStatus(ResultConstant.SUCSESS);
            return result;
        } else {
            throw new AuthException(ResultCode.OK_CONTENT_NO, "mini.userorpasserror");
        }


    }

    @PostMapping("/wxMini")
    @ResponseBody
    public Result wxMini(HttpServletRequest request, @RequestBody @Valid WxMiniConfig wxMiniConfig) throws SerkolProjectException, WxErrorException {
        tokenUtils = new TokenUtils(logService);
        String terminal = request.getHeader("terminal");
        System.out.println(wxMiniConfig);
        LoginLog loginLog = wxMiniConfig.getLoginLog();
        loginLog.setTerminal(NumberUtils.toInt(terminal.isEmpty() ? String.valueOf('1') : String.valueOf(terminal), 0));
        // loginLog.setIp(getCliectIp(request));
        Result result = new Result();



        loginLog.setIp(getCliectIp(request));

        WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(wxMiniConfig.getCode());
        String openid = session.getOpenid();
        String sessionKey = session.getSessionKey();
        System.out.println(openid);
        System.out.println(wxMiniConfig);
        Users byLogin = userService.findByLogin(openid);

        Map<String, Object> mapLogin = new HashMap<>();
        if (byLogin == null) {
            WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionKey, wxMiniConfig.getEncryptedData(), wxMiniConfig.getIv());

            System.out.println(userInfo);
            if (userInfo != null) {

                Users usersDetail = ParseUtils.parseUsersDetail(userInfo);

                usersDetail.setOpenid(openid);
                if (wxMiniConfig.getParentUserId() != null) {
                    boolean isUser = userService.isUsers(wxMiniConfig.getParentUserId());
                    if (isUser) {
                        usersDetail.setParentUserId(wxMiniConfig.getParentUserId());

                    }
                } else {
                    result.setStatus(ResultConstant.FAIL);
                    return result;
                }
                byLogin = userService.findByLoginAndInsert(usersDetail);

                userService.updateById(byLogin);
                loginLog.setOpenId(byLogin.getOpenid());
                mapLogin = getToken(byLogin, loginLog, sessionKey);

                //   wxMaService.getUserService().setUserStorage(mapText, sessionKey, openid);
                result.setData(mapLogin);
                result.setStatus(ResultConstant.SUCSESS);
            } else {
                result.setStatus(ResultConstant.FAIL);
            }
            //  wxMaService.getUserService().setUserStorage(map, sessionKey,openid);

        } else {
            if (wxMiniConfig.getParentUserId() != null) {
                boolean isUser = userService.isUsers(wxMiniConfig.getParentUserId());
                if (isUser) {
                    byLogin.setParentUserId(wxMiniConfig.getParentUserId());
                    userService.saveOrUpdate(byLogin);



                }

            }
            loginLog.setOpenId(byLogin.getOpenid());
            mapLogin = getToken(byLogin, loginLog, sessionKey);
            result.setData(mapLogin);
            result.setStatus(ResultConstant.SUCSESS);
        }
        //   wxMaService.getUserService().
        return result;
    }


    @Transactional
    @PostMapping("/wxRegesterMini")
    @ResponseBody
    public Result wxRegesterMini(HttpServletRequest request, @RequestBody @Valid WxMiniRegesterConfig wxMiniConfig) throws SerkolProjectException, WxErrorException, AuthException {
        tokenUtils = new TokenUtils(logService);
        UsersRegesterInfo regesterInfo = wxMiniConfig.getRegesterInfo();
        //    String terminal = request.getHeader("terminal");
        //  System.out.println(wxMiniConfig);
        LoginLog loginLog = wxMiniConfig.getLoginLog();
        // loginLog.setIp(getCliectIp(request));
        Result result = new Result();
        Long agentIdDefault = 1L;


        //    loginLog.setTerminal(NumberUtils.toInt(terminal.isEmpty() ? String.valueOf('1') : String.valueOf(terminal), 0));
        loginLog.setIp(getCliectIp(request));

        WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(wxMiniConfig.getCode());
        String openid = session.getOpenid();
        String sessionKey = session.getSessionKey();
        System.out.println(openid);
        System.out.println(wxMiniConfig);
        Users byLogin = userService.findByLogin(openid);
        loginLog.setOpenId(openid);
        Map<String, Object> mapLogin = new HashMap<>();
        if (byLogin == null) {
            WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionKey, wxMiniConfig.getEncryptedData(), wxMiniConfig.getIv());

            System.out.println(userInfo);
            if (userInfo != null) {

                Users usersDetail = ParseUtils.parseUsersDetail(userInfo);

                usersDetail.setOpenid(openid);
                if (regesterInfo.getParentUserId() != null) {
                    boolean isUser = userService.isUsers(regesterInfo.getParentUserId());
                    if (isUser) {
                        usersDetail.setParentUserId(regesterInfo.getParentUserId());

                    }
                }
                if (StringUtils.isNotEmpty(regesterInfo.getPassword())) {
                    MD5 md5 = MD5.create();
                    String s = md5.digestHex(regesterInfo.getPassword());
                    usersDetail.setUserPassword(s);
                }
                //  usersDetail.setUserPassword(regesterInfo.getPassword());
                usersDetail.setPhone(regesterInfo.getPhone());
                //   usersDetail.setInvite("");


                byLogin = userService.findByLoginAndInsert(usersDetail);
                if (byLogin.getId() > 0) {

                        result.setData(mapLogin);
                        result.setStatus(ResultConstant.SUCSESS);

                } else {
                    result.setStatus(ResultConstant.FAIL);
                }
            } else {
                result.setStatus(ResultConstant.FAIL);
            }
            //  wxMaService.getUserService().setUserStorage(map, sessionKey,openid);

        } else {

                    throw new AuthException(ResultCode.REQUEST_ERROR_UNAUTHORIZED);
                }




        //   wxMaService.getUserService().
        return result;
    }


    @PostMapping("/wxMiniAuto")
    @ResponseBody
    public Result wxMiniAuto(HttpServletRequest request, @RequestBody @Valid WxMiniConfig wxMiniConfig) throws SerkolProjectException, WxErrorException, AuthException {
        tokenUtils = new TokenUtils(logService);
        System.out.println(wxMiniConfig);
        //  String terminal = request.getHeader("terminal");
        LoginLog loginLog = wxMiniConfig.getLoginLog();
        // loginLog.setIp(getCliectIp(request));
        //  loginLog.setTerminal(NumberUtils.toInt(terminal.isEmpty() ? String.valueOf('1') : String.valueOf(terminal), 0));
        loginLog.setIp(getCliectIp(request));
        System.out.println(wxMaService.getWxMaConfig().getAppid());
        WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(wxMiniConfig.getCode());
        String openid = session.getOpenid();
        String sessionKey = session.getSessionKey();
        System.out.println(openid);
        System.out.println(wxMiniConfig);
        Users byLogin = userService.findByLogin(openid);
        Map<String, Object> mapLogin = new HashMap<>();
        if (byLogin != null) {
            loginLog.setOpenId(byLogin.getOpenid());
            mapLogin = getToken(byLogin, loginLog, sessionKey);
            return Result.ok(mapLogin);
        } else {


            throw new AuthException(ResultCode.OK_CONTENT_NO, "mini.regesterrecommended");
        }
        //   wxMaService.getUserService().

    }

    private Map<String, Object> getToken(Users usersDetail, LoginLog loginLog, String sessionKey) {


        loginLog.setUserId(usersDetail.getId());
        loginLog.setUserName(usersDetail.getNickname());

        loginLog.setParentUserId(usersDetail.getParentUserId());
        loginLog.setCreateDate(new Date());
        loginLog.setRoleId(usersDetail.getRoleId());
        System.out.println("--------------getToken--------------");
        System.out.println(loginLog);
        String token = tokenUtils.getToken(loginLog);

        Map<String, Object> map = ParseUtils.parseTokenDetail(usersDetail);

        map.put("admin", usersDetail.getIsAdmin());
        map.put("token", token);
        map.put("sessionKey", sessionKey);
        String message ="Helllo"; //I18nUtil.getMessage("system.company");
        if (usersDetail.getParentUserId() != null) {
            Users parentUser = userService.findByUserId(usersDetail.getParentUserId());
            System.out.println("PARENT_USER");
            System.out.println(parentUser);
            Map<String, Object> userMap = new HashMap<>();
            if (parentUser == null) {

                userMap.put("nickname", message);
                userMap.put("userName", message);
                userMap.put("name", message);
                userMap.put("avatar", usersDetail.getAvatar());
                userMap.put("flag", false);
            } else {

                userMap.put("nickname", parentUser.getNickname());
                userMap.put("userName", parentUser.getUserName());
                userMap.put("avatar", parentUser.getAvatar());
                userMap.put("id", parentUser.getId());

                userMap.put("flag", true);
            }

            map.put("parentUser", userMap);

        } else {
            Map<String, Object> userMap = new HashMap<>();
            userMap.put("name", message);
            userMap.put("nickname", message);
            userMap.put("userName", message);
            userMap.put("avatar", usersDetail.getAvatar());
            userMap.put("flag", false);
            userMap.put("id", 0);
            map.put("parentUser", userMap);
        }

        return map;

    }

    //phone
    @GetMapping("/byPhone")
    @ResponseBody
    public Result byPhone(@RequestParam(name = "phone", defaultValue = "") String phone) {
        if (StringUtils.isNotEmpty(phone)) {
            boolean phoneValid = userService.isPhoneValid(phone);
            System.out.println("APPPPP:" + phoneValid);
            return phoneValid ? Result.failure() : Result.ok();
        } else {
            return Result.ok();
        }


    }

    //phone




}
